#include "FastEspnow.h"

ESPNOW &Espnow = Espnow.getInstance();

void log_d_u8_array(const char *TAG, const uint8_t *arr, int size)
{
    char buffer[256] = {0};
    uint8_t offset = 0;
    for (int i = 0; i < size; i++)
        offset += snprintf(buffer + offset, sizeof(buffer) - offset, "%d(%02X) ", arr[i], arr[i]);
    log_d("%s "
          "%s",
          TAG, buffer);
}

/// @brief 检查校验和 false : 错误   true :  正确
bool ESPNOW::checkSum(const uint8_t *buf, uint8_t len)
{
    uint8_t t;
    for (int i = 0; i < (len - 1); i++)
        t += *(buf + i);

    if (t == buf[len - 1])
        return true;
    else
        return false;
}

// callback when data is recv from Master
void ESPNOW::OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int dataLen)
{
    // 1. 检查数据包是否有效
    if (*(data + 0) != FRAME_HEARTBEAT_1 || *(data + 1) != FRAME_HEARTBEAT_2 || !p->checkSum(data, dataLen))
        return;

    // 2.0 将接收到的数据转换为 指令结构体
    MESSAGE msg(const_cast<uint8_t *>(data));

    // 2.1 如果收到心跳包 跳过这个包
    if (msg.cmd == CMD_HeartBeat)
        return;

    // 2.2 复制地址到 msg 中
    memcpy(msg.address, mac_addr, 6);

    // 2.3 打印接收到的数据
    log_d_u8_array("\tReceived DATA ", data, dataLen);

    // 3. 查询节点是否已经配对
    int index = p->findPeer(mac_addr);

    /* ------------------------------------------- 握手部分 ------------------------------------------- */
    // 4. 设备开始扫描, 并且接收到 握手包
    if (msg.cmd == CMD_HANDSHAKE && p->sacnStatus == readyConnect)
    {
        // 4.1. 如果是一个新设备
        if (p->findPeer(mac_addr) == -1)
        {
            log_d("\t\tReceived A [CMD_HANDSHAKE]");
            p->addPeer(mac_addr, msg.sn);          // 添加地址
            p->sacnStatus = receivedBroadcast;     // 收到广播包
            memcpy(p->handShakeAddr, mac_addr, 6); // 复制广播包地址

            memcpy(p->tconfigArray, msg.data, msg.len); // 复制配置数组
            p->tconfigArrayLength = msg.len;            // 复制配置数组长度
        }
        return;
    }

    // 5. 如果设备收到 握手应答
    else if (msg.cmd == CMD_HANDSHAKE_ASK && p->sacnStatus == readyConnect)
    {
        memcpy(p->handShakeAddr, mac_addr, 6); // 复制广播包地址

        // 5.1 发送握手应答的设备还没有被加入列表, 就添加到已配对列表里面
        if (p->findPeer(mac_addr) == -1)
        {
            p->addPeer(mac_addr, msg.sn);
            log_d("\t\tReceived Ask Packet! Add Peer");
        }
        // 5.2 更新扫描状态为 已经连接, 扫描进程获取到状态后, 将触发 扫描结束 和 设备上线 事件, 并关闭扫描任务
        memcpy(p->tconfigArray, msg.data, msg.len); // 复制配置数组
        p->tconfigArrayLength = msg.len;            // 复制配置数组长度

        p->sacnStatus = hasConnected;

        return;
    }

    // 6. 如果还收到 握手包 或者 握手应答, 因为已经添加完毕 直接返回
    else if (msg.cmd == CMD_HANDSHAKE_ASK || msg.cmd == CMD_HANDSHAKE)
        return;

    // 7. 如果发送方并没有在配对列表里，通知对方删除本机
    /*
        情况说明: 假设设备 A 是接收器，可以通过上位机删除所连接的节点，设备 B 是设备 A 链接的节点之一，B 进入 休眠后，上机位删除设备A中的 B 节点，此时，B 上线后,
        有 A 的地址，而 A 没有，出于合理考虑，需要通知设备 B 删除 A 。重新链接其他接收器
    */
    if (index == -1)
    {
        log_d("\t\tSend CMD_DISCONNECT!  Notify Peer Delete Each Other! ");
        esp_now_peer_info_t peerInfo = {};
        memcpy(&peerInfo.peer_addr, mac_addr, 6);
        esp_now_add_peer(&peerInfo);
        p->sendMessage(peerInfo.peer_addr, CMD_DISCONNECT);
        esp_now_del_peer(peerInfo.peer_addr); // 清除节点
        return;
    }

    //  5. 将接收到的数据发送给队列
    xQueueSend(p->q_rec_msg, &msg, 0);
}

// /***************************************************************************************************
//  * @brief     ESPNow 发送后调用的回调函数。
//  * @param     macAddr 目标地址
//  * @param     status 发送状态
//  *
//  * @attention 如果发送失败超过一定次数, 删除该节点,需注意, 即便返回 success 也不代表目标节点有接收到数据
//  **************************************************************************************************/
void ESPNOW::onDataSent(const uint8_t *macAddr, esp_now_send_status_t status)
{
    // 1.如果发送目标的地址不在已配对列表，就退出
    int peerIndex = p->findPeer(macAddr);
    if (peerIndex == -1)
        return;

    // 2.发送成功就退出
    if (status == ESP_NOW_SEND_SUCCESS)
    {
        p->peers[peerIndex].failures = 0;
        p->peers[peerIndex].status = 1;

        if (p->peers[peerIndex].pre_status != p->peers[peerIndex].status)
        {
            // if (p->_peerActive_cb != NULL && p->peers[peerIndex].pre_status == 0)
            //     p->_peerActive_cb(p->peers[peerIndex]);

            p->peers[peerIndex].pre_status = p->peers[peerIndex].status;
        }
        return;
    }

    // 3.如果发送失败， failures +1
    p->peers[peerIndex].failures++;

    log_d("\t\tSend Failed %d Times SN:%02X", p->peers[peerIndex].failures, p->peers[peerIndex].sn);

    // 4.如果发送失败次数超过指定次数，就挂起掉这个节点
    if (p->peers[peerIndex].failures >= FAILURES_TIMES)
    {
        p->peers[peerIndex].status = 0; // 设备挂起
        p->peers[peerIndex].failures = 0;

        // 5. 调用设备挂起回调
        if (p->peers[peerIndex].pre_status != p->peers[peerIndex].status)
        {
            p->peers[peerIndex].pre_status = p->peers[peerIndex].status;
            if (p->_peerSupend_cb != NULL)
                p->_peerSupend_cb(p->peers[peerIndex]);
            log_d("\t\tPeer Suspend SN:%02X", p->peers[peerIndex].sn);
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 挂起
void ESPNOW::supend()
{
    log_d("\t\tSend Suspend CMD!");
    for (int i = 0; i < peer_count; i++)
    {
        sendMessage(peers[i].address, CMD_SUSPEND);
    }
}

void ESPNOW::active()
{
    log_d("\t\tSend Active CMD!");
    for (int i = 0; i < peer_count; i++)
    {
        MESSAGE msg(sn, CMD_ACTIVE, myConfigArrayLength, myConfigArray); // 广播包
        sendMessage(peers[i].address, msg);
    }
}

// 返回激活节点列表
void ESPNOW::getActivePeers()
{
    ///////////////////////
}

/// @brief  往特定地址 address 发送信息 msg
void ESPNOW::sendMessage(const uint8_t *address, MESSAGE msg)
{
    if (xSemaphoreTake(x_espnow_send, timeOut) == pdPASS)
    {
        esp_err_t result = esp_now_send(address, msg.toArry(), msg.length());

        // 如果发送的指令是 承诺指令, 需要保存到 承诺数据数组
        if (msg.cmd == CMD_PROMISE)
        {
            log_d("\t\tSend Promise, Push it Into Promise[]! ");
            // 3. 先判断之前是否已经有保存该 SN 的未发送信息
            for (uint8_t i = 0; i < promiseCount; i++)
            {
                if (msg.sn == promise[i].sn)
                {
                    // 3.1之前已经有存储, 那就更新数据
                    log_d("\t\tIt Is A Old Promise! ");

                    promise[i].cmd = msg.cmd;
                    promise[i].len = msg.len;
                    memcpy(promise[i].data, msg.data, msg.len);
                    promise[i].sum = msg.sum;
                    // 3.2 结束操作
                    goto END;
                }
            }
            // 2.0 如果之前没有保存该节点的的信息, 添加到 待发送列表中
            log_d("\t\tIt Is A New Promise! ");
            memcpy(promise[promiseCount].head, msg.head, 2);
            promise[promiseCount].sn = msg.sn;
            promise[promiseCount].cmd = msg.cmd;
            promise[promiseCount].len = msg.len;
            memcpy(promise[promiseCount].data, msg.data, msg.len);
            promise[promiseCount].sum = msg.sum;
            // memcpy(promise[promiseCount].address, msg.address, 6);
            promiseCount++;
        }

        vTaskDelay(SEND_INTERVAL); // 只要大于10ms就行， 不过35ms能保证HID传输不丢数据, 具体的值要看指令长度
    END:
        xSemaphoreGive(x_espnow_send);

        if (result != ESP_NOW_SEND_SUCCESS)
            log_d("\t\tSend Faild, Error: %d!", result);
    }
}

/// @brief  发送包括地址不定长度数据
void ESPNOW::sendMessage(const uint8_t *address, uint8_t _cmd, uint8_t _len, ...)
{
    uint8_t data[_len];
    va_list args;
    va_start(args, _len); // args指向栈顶
    for (int i = 0; i < _len; ++i)
        data[i] = va_arg(args, int);
    va_end(args);

    MESSAGE msg(sn, _cmd, _len, data);
    msg.setSum();
    return sendMessage(address, msg);
}

/// @brief 发送广播包 Task
void ESPNOW::scan_method()
{
    // 1. 创建并添加广播节点
    esp_now_peer_info_t peer = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0, CHANNEL, ESP_IF_WIFI_STA, false, 0};
    esp_now_add_peer(&peer);

    MESSAGE msg(sn, CMD_HANDSHAKE, myConfigArrayLength, myConfigArray); // 广播包
    sacnStatus = openConnect;                                           // 开启接收
    uint8_t loopTimes = 0;                                              // 发送循环次数

    log_d("\t\tStart Scaning!");

    // 2.触发 开始扫描 事件
    if (_scan_start_cb != NULL)
        _scan_start_cb();

    while (1)
    {
        // 3. 如果收到握手包
        if (sacnStatus == receivedBroadcast)
        {
            // 4. 触发 扫描结束 事件, true 表示有扫描到设备
            log_d("\t\tFind Peer! Peer Online ");
            if (_scan_stop_cb != NULL)
                _scan_stop_cb(true);

            // 5. 获取 刚添加的节点在列表中的位置
            uint8_t idx = findPeer(handShakeAddr);

            // 6. 触发 设备上线 事件
            if (_peerOnline_cb != NULL)
                _peerOnline_cb(peers[idx], tconfigArray, tconfigArrayLength);

            // 发送 5 次应答包，这里没有在接收函数里面对 ASK 再次应答，所以多发送几次，避免没收到
            for (size_t i = 0; i < 5; i++)
            {
                MESSAGE askMsg(sn, CMD_HANDSHAKE_ASK, myConfigArrayLength, myConfigArray); // 广播包
                sendMessage(handShakeAddr, askMsg);

                log_d("\t\tSend A CMD_HANDSHAKE_ASK To:[%02X:%02X:%02X:%02X:%02X:%02X]",
                      handShakeAddr[0], handShakeAddr[1], handShakeAddr[2], handShakeAddr[3], handShakeAddr[4], handShakeAddr[5]);

                vTaskDelay(PACKET_INTERVAL);
            }

            sacnStatus = closeConnect;        // 关闭接收
            esp_now_del_peer(peer.peer_addr); // 清除节点
            vTaskDelete(NULL);                // 退出任务
        }

        // ---------------------------------- 如果接收到ASK, 表示已经找到节点，退出 ----------------------------------
        if (sacnStatus == hasConnected)
        {
            // 扫描结果回调，true 表示找到设备
            if (_scan_stop_cb != NULL)
                _scan_stop_cb(true);

            uint8_t idx = findPeer(handShakeAddr);
            if (_peerOnline_cb != NULL)
                _peerOnline_cb(peers[idx], tconfigArray, tconfigArrayLength);

            sacnStatus = closeConnect;        // 关闭接收
            esp_now_del_peer(peer.peer_addr); // 清除节点
            vTaskDelete(NULL);                // 退出任务
        }

        // ---------------------------------- 如果超过发送次数就退出扫描 ----------------------------------
        if (loopTimes > MAX_SCAN_TIMES)
        {
            log_d("\t\tPeer Not Found ,About To Exit!");

            // 扫描结果回调，false 表示没找到设备
            if (_scan_stop_cb != NULL)
                _scan_stop_cb(false);

            sacnStatus = closeConnect;        // 关闭接收
            esp_now_del_peer(peer.peer_addr); // 清除节点
            vTaskDelete(NULL);                // 退出任务
        }

        // ---------------------------------- 发送广播包 ----------------------------------
        sendMessage(peer.peer_addr, msg);

        log_d("\t\tScaning "
              "%d times ... ... ",
              MAX_SCAN_TIMES - loopTimes);
        loopTimes++;

        vTaskDelay(PACKET_INTERVAL);
    }
}
/// @brief  发送广播包
void ESPNOW::scan()
{
    if (sacnStatus == closeConnect)
        xTaskCreate(this->s_scan_method, "发送广播包", 1024 * 5, this, 1, nullptr);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/***************************************************************************************************
 * @brief     添加节点， 并且更新配对列表信息
 * @param     mac  节点地址
 * @param     type 设备类型
 * @param     sn   设备sn
 *
 **************************************************************************************************/
void ESPNOW::addPeer(const uint8_t *mac, uint16_t sn)
{
    // 1. 新建节点
    esp_now_peer_info_t peerInfo = {};
    memcpy(&peerInfo.peer_addr, mac, 6);
    // 2.尝试添加到节点中
    if (esp_now_is_peer_exist(mac))
        esp_now_del_peer(mac);
    if (esp_err_t e = esp_now_add_peer(&peerInfo) == ESP_OK)
    {
        // 3.将地址也保存到已配对列表中
        addPeerToconfig(mac, sn);
        log_d("\t\tAdded Peer [%02X][%02X,%02X,%02X,%02X,%02X,%02X] Successfully!",
              sn, peerInfo.peer_addr[0], peerInfo.peer_addr[1], peerInfo.peer_addr[2], peerInfo.peer_addr[3], peerInfo.peer_addr[4], peerInfo.peer_addr[5]);
    }
    else
    {
        log_d("\t\tPeer Added Failed! Error Code = %02X", e);
    }
}

/// @brief  根据设备在 peers 列表中的序号 peerIndex ，删除节点
void ESPNOW::removePeer(int peerIndex, bool notifyPeer)
{
    // 通知对方删除
    if (notifyPeer)
    {
        sendMessage(peers[peerIndex].address, CMD_DISCONNECT);
        vTaskDelay(2);
    }
    // 1. 尝试从节点列表中清除目标地址
    if (esp_now_del_peer(peers[peerIndex].address) == ESP_OK)
    {
        log_d("\t\tRemove Peer [%02X] Successfully! There Are Currently %d Peers In Total",
              peers[peerIndex].sn, peer_count - 1);

        // 2. 清除 promisep[] 中对应的信息
        for (uint8_t i = 0; i < promiseCount; i++)
        {
            if (peers[peerIndex].sn == promise[i].sn)
            {
                log_d("\tRemove Peer Promise!");
                // 2.1 不在列表中的最后一个. 就得进行移位操作
                if (i < promiseCount - 1)
                {
                    for (uint8_t k = i; k < promiseCount; k++)
                    {
                        promise[k].sn = promise[k + 1].sn;
                        promise[k].cmd = promise[k + 1].cmd;
                        promise[k].len = promise[k + 1].len;
                        memcpy(promise[k].data, promise[k + 1].data, promise[k + 1].len);
                        promise[k].sum = promise[k + 1].sum;
                        // memcpy(promise[k].address, promise[k + 1].address, 6);
                    }
                    promiseCount--;
                }
                // 2.2 设备正好在列表的最后一个, 直接将 promiseCount - 1 就行
                else
                {
                    promiseCount--;
                }
            }
        }

        // 3. 清除已配对列表 peers 中的值，并且 peerCount - 1
        removePeerToconfig(peerIndex);
    }
    else
    {
        log_d("\t\tPeer Remove Faild! [%02X][%02X,%02X,%02X,%02X,%02X,%02X]",
              peers[peerIndex].sn,
              peers[peerIndex].address[0], peers[peerIndex].address[1],
              peers[peerIndex].address[2], peers[peerIndex].address[3],
              peers[peerIndex].address[4], peers[peerIndex].address[5]);
    }
}

/// @brief 删除所有节点
void ESPNOW::clearAllPeers()
{
    log_d("\tClear All Peers!");

    for (int i = 0; i < peer_count; i++)
    {
        //  触发 设备离线 事件
        if (_peerOffline_cb != NULL)
            _peerOffline_cb(peers[i]);

        // 发送 设备离线 信号
        sendMessage(peers[i].address, CMD_DISCONNECT);
        esp_now_del_peer(peers[i].address);
    }

    // 清除全部配置信息
    clearAllPeersOnconfig();

    // 清除所有 promise 信息
    promiseCount = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/***************************************************************************************************
 *@brief 线程处理函数
 *@param commad 指令类型
 ***************************************************************************************************/
void ESPNOW::receive_method()
{
    // 5.3 如果之前有配对过，取出之前配对的地址
    if (peer_count > 0)
    {
        for (int i = 0; i < peer_count; i++)
        {
            // 5.4 新建节点
            esp_now_peer_info_t peer = {};
            memcpy(&peer.peer_addr, peers[i].address, 6);
            esp_now_add_peer(&peer);

            // 5.5调用配对回调
            // if (_peerOnline_cb != NULL)
            //     _peerOnline_cb(peers[i]);

            log_d("\tFind Peer \t"
                  "[%d] SN:[%02X]  Address :[%02X:%02X:%02X:%02X:%02X:%02X]",
                  i, peers[i].sn,
                  peers[i].address[0], peers[i].address[1], peers[i].address[2],
                  peers[i].address[3], peers[i].address[4], peers[i].address[5]);
        }
    }
    else
    {
        log_d("\tPeer Not Found... ...");
    }

    MESSAGE msg;
    while (1)
    {
        // 1. 接收数据  注意，这边消息队列等待时间会让程序在这边一直等待，此处设置为 0
        if (xQueueReceive(q_rec_msg, (void *)&msg, 0) == pdPASS)
        {
            int index = p->findPeer(msg.sn);

            // 2. 如果收到 断开请求包. 并且这个设备在列表中， 就删除发送这个信息的设备,
            if (msg.cmd == CMD_DISCONNECT)
            {
                log_d("\tReceived CMD_DISCONNECT! Delete This Peer! ");

                // 2.1 触发 设备离线 事件
                if (p->_peerOffline_cb != NULL)
                    p->_peerOffline_cb(p->peers[index]);

                // 2.2 删除节点，并且通知对方不用回复，避免无限轮回
                p->removePeer(index, false);
            }

            // 3. 如果收到 挂起请求 .并且这个设备在列表中， 就挂起发送这个信息的设备,
            else if (msg.cmd == CMD_SUSPEND)
            {
                log_d("\t\tReceived CMD_SUSPEND! Suspend This Peer! ");
                p->peers[index].status = 0;
                p->peers[index].pre_status = 0;
                if (p->_peerSupend_cb != NULL)
                    p->_peerSupend_cb(p->peers[index]);
            }

            // 4. 如果是激活请求包.并且这个设备在列表中， 就激活发送这个信息的设备,
            else if (msg.cmd == CMD_ACTIVE)
            {
                log_d("\t\tReceived CMD_ACTIVE! Active This Peer! ");

                p->peers[index].status = 1;
                p->peers[index].pre_status = 1;

                // 4.1 检测激活的这个设备是否有未发送的信息
                p->checkPromise(msg.address, msg.sn);

                // 4.2 触发 设备激活 事件
                if (p->_peerActive_cb != NULL)
                    p->_peerActive_cb(p->peers[index], msg.data, msg.len);
            }

            // 5.如果收到的是 承诺指令 需要进行应答
            else if (msg.cmd == CMD_PROMISE)
            {
                log_d("\tReceived CMD_PROMISE! ");
                // 5.1 发送 承诺应答指令
                p->sendMessage(msg.address, CMD_PROMISE_ASK);

                // 5.2 触发 接收数据 事件
                if (_recMessage_cb != NULL)
                    _recMessage_cb(msg.address, msg.sn, msg.cmd, msg.len, msg.data); // 接收回调
            }

            // 6.如果收到的是 承诺应答 就把 promise[] 中相关数据删除
            else if (msg.cmd == CMD_PROMISE_ASK)
            {
                for (uint8_t i = 0; i < promiseCount; i++)
                {
                    // 1.1 如果该 SN 确实有待发送信息 ,尝试进行发送
                    if (msg.sn == promise[i].sn)
                    {
                        log_d("\tReceived CMD_PROMISE_ASK! Pull It From Promise[]");
                        // 1.3 不在列表中的最后一个. 就得进行移位操作
                        if (i < promiseCount - 1)
                        {
                            for (uint8_t k = i; k < promiseCount; k++)
                            {
                                promise[k].sn = promise[k + 1].sn;
                                promise[k].cmd = promise[k + 1].cmd;
                                promise[k].len = promise[k + 1].len;
                                memcpy(promise[k].data, promise[k + 1].data, promise[k + 1].len);
                                promise[k].sum = promise[k + 1].sum;
                                // memcpy(promise[k].address, promise[k + 1].address, 6);
                            }
                            promiseCount--;
                        }
                        // 设备正好在列表的最后一个, 直接将 promiseCount - 1 就行
                        else
                        {
                            promiseCount--;
                        }
                    }
                }
            }

            // 7. 收到的是普通的指令包
            else
            {
                // 7.1 检测发送信息的这个设备是否有未发送的信息
                p->checkPromise(msg.address, msg.sn);

                if (_recMessage_cb != NULL)
                    _recMessage_cb(msg.address, msg.sn, msg.cmd, msg.len, msg.data); // 接收回调
            }
        }

        vTaskDelay(1);
    }
}

/// @brief 初始化 ESPNOW
void ESPNOW::begin(uint16_t _sn, void *config, uint8_t len, bool isFristTime)
{
    loadConfigurayion();
    sn = _sn;

    myConfigArrayLength = len;
    memcpy(myConfigArray, config, myConfigArrayLength);

    // Serial.printf("myConfigArrayLength: %d\n", myConfigArrayLength);
    // Serial.printf("打印转换后的数组:");
    // for (size_t i = 0; i < len; i++)
    //     Serial.printf("%02x ", myConfigArray[i]);
    // Serial.printf("\n");

    // 首次烧录需要设定初始值. 后续配置信息由上位机更新，
    // 第二次烧录注释掉初始设定.
    if (isFristTime)
    {
        clearAllPeersOnconfig();
    }

    WiFi.mode(WIFI_AP_STA);
    WiFi.disconnect();

    if (esp_now_init() == ESP_OK)
        log_d("\t\tESPNow Init Success!");

    // 接收回调
    esp_now_register_recv_cb(OnDataRecv);
    esp_now_register_send_cb(onDataSent);

    // 接收处理线程
    if (xTaskCreatePinnedToCore(this->s_receive_method, "peerTask", 1024 * 5, this, 2, NULL, 1) == pdPASS)
        log_d("\t\tPeerTask Created Surress! SN:%02X", sn);
    else
        log_d("\t\tPeerTask Created Faild! SN:%02X", sn);

    // 创建MUTEX
    x_espnow_send = xSemaphoreCreateMutex();

    // 向所有节点发送唤醒指令
    active();
}

void ESPNOW::openHeartBeat(uint16_t interval)
{
    heartbeatHandle = xTimerCreate("heartbeat Timer",
                                   interval,                // 定时器时间
                                   pdTRUE,                  // 模式, pdTRUE 重复执行  pdFALSE 只执行一次
                                   (void *)0,               // 定时器ID
                                   [](TimerHandle_t xTimer) // 回调函数
                                   {
                                       for (int i = 0; i < p->peer_count; i++)
                                       {
                                           p->sendMessage(p->peers[i].address, CMD_HeartBeat);
                                       }
                                   });
    xTimerStart(heartbeatHandle, portMAX_DELAY);
}
void ESPNOW::closeHeartBeat()
{
    xTimerDelete(heartbeatHandle, portMAX_DELAY);
}

void ESPNOW::checkPromise(const uint8_t *macAddr, uint16_t sn)
{
    // 1. 查看该 SN 是否有待发送的信息
    for (uint8_t i = 0; i < promiseCount; i++)
    {
        // 1.1 如果该 SN 确实有待发送信息 ,尝试进行发送
        if (sn == promise[i].sn)
        {
            log_d("\t\tThis Peer Have A Promise Data! Try To Send Message");
            sendMessage(macAddr, promise[i]);
        }
    }
}
